{
    "cells": [
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "cc494c10",
            "metadata": {},
            "source": [
                "# FullControl overview\n",
                "\n",
                "FullControl is used to design changes to the ***state*** of ***things***\n",
                "\n",
                "- ***state*** is any property of interest that can change (position, speed, power, temperature, etc.)\n",
                "\n",
                "- ***things*** are anything with ***state*** - this initial release of FullControl is focused on ***things*** being extrusion 3D printers that are instructed by gcode\n",
                "\n",
                "gcode is a list of instructions that change the ***state*** of a ***thing*** (3D printer, laser cutter, etc.)\n",
                "\n",
                "a FullControl ***design*** dictates how the ***states*** of ***things*** change during a procedure (e.g. a manufacturing procedure)\n",
                "\n",
                "for this release, the FullControl ***design*** is a 1D list of sequential 'steps' to change ***state***. The designer creates simple python code to generate the list. Each 'step' in the list is created using pre-defined templates for objects built into FullControl (described in later tutorial notebooks)\n",
                "\n",
                "FullControl inspects the ***design*** and converts it into a ***result***\n",
                "\n",
                "a ***result*** is gcode or a 3D plot in this initial release, but future releases will allow different types of ***designs*** and ***results***. \n",
                "- e.g. to FEA simulations\n",
                "- e.g. to documentation to support certification\n",
                "\n",
                "at present, gcode can be formatted for a selection of printers and the 3D plot is implemented in plotly, but the range of printers is intended to be extended along with plotting software options\n",
                "\n",
                "FullControl contains a set of tools to guide and support the generation of the ***design*** and the ***result***. e.g. geometry functions to support the generation of the ***design***. e.g. different variants of the gcode ***result*** to suit different printers\n",
                "\n",
                "<*this document is a jupyter notebook - if they're new to you, check out how they work:\n",
                "[link](https://www.google.com/search?q=ipynb+tutorial),\n",
                "[link](https://jupyter.org/try-jupyter/retro/notebooks/?path=notebooks/Intro.ipynb),\n",
                "[link](https://colab.research.google.com/)*>\n",
                "\n",
                "*run all cells in this notebook in order (keep pressing shift+enter)*"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "5c732abb",
            "metadata": {},
            "source": [
                "# scope of this notebook\n",
                "\n",
                "this notebook gives a brief overview of FullControl capabilities with minimal technical explanations\n",
                "\n",
                "other tutorial notebooks give full details of the FullControl features demonstrated here"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "bde1c3eb",
            "metadata": {},
            "source": [
                "## I - import the FullControl python package\n",
                "\n",
                "this gives you access to FullControl's functions and objects, etc.\n",
                "\n",
                "make sure FullControl is installed first (very simple) - see the [github readme](https://github.com/FullControlXYZ/fullcontrol) for instructions"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "281a6de8-9f5e-4861-a1f4-f60de323e616",
            "metadata": {},
            "outputs": [],
            "source": [
                "if 'google.colab' in str(get_ipython()):\n  !pip install git+https://github.com/FullControlXYZ/fullcontrol --quiet\nimport fullcontrol as fc"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "72761fb2",
            "metadata": {},
            "source": [
                "## II - create a FullControl ***design***\n",
                "\n",
                "as described above, the ***design*** is a list of steps using pre-defined FullControl objects as templates for ***state***-changes \n",
                "\n",
                "minimal python knowledge is required\n",
                "\n",
                "this notebook introduces basic python features/functions including 1D arrays (*'lists'*), *'append'* and *'extend'* functions, for-loops and the *'math'* module\n",
                "\n",
                "complex FullControl designs can be created with only these functions"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "c78aab2b",
            "metadata": {},
            "source": [
                "#### the ***design*** is a list of steps\n",
                "\n",
                "in this example, we create a three-step 'design' \n",
                "each step uses a FullControl 'Point' object, which tells the printer where to move to"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "4c77c8ec",
            "metadata": {},
            "outputs": [],
            "source": [
                "point_1 = fc.Point(x=10, y=10, z=0)\n",
                "point_2 = fc.Point(x=20, y=10, z=0)\n",
                "point_3 = fc.Point(x=10, y=20, z=0)\n",
                "steps = [point_1, point_2, point_3]"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "fdf8af18",
            "metadata": {},
            "source": [
                "#### transform the ***design*** into a 'gcode' ***result***\n",
                "\n",
                "use the fc.transform() function to transform the list of steps into gcode, then use the print() function to print the gcode to screen\n",
                "\n",
                "saving gcode to a .gcode file directly is demonstrated later in this notebook"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "57cb2035-f44a-4378-8d60-0c9b5746bc12",
            "metadata": {},
            "outputs": [],
            "source": [
                "steps = [point_1, point_2, point_3]\n",
                "gcode = fc.transform(steps, 'gcode', fc.GcodeControls(printer_name='generic'), show_tips=False)\n",
                "print(gcode)"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "6ae75b68",
            "metadata": {},
            "source": [
                "#### use the python 'append' and 'extend' functions to add steps to a ***design***"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "8f24063d",
            "metadata": {},
            "outputs": [],
            "source": [
                "# first, create an empty list\n",
                "steps = []\n",
                "\n",
                "# then add single items to it with 'append'\n",
                "steps.append(fc.Point(x=10, y=10, z=0))\n",
                "steps.append(fc.Point(x=20))\n",
                "steps.append(fc.Point(x=10, y=20))\n",
                "\n",
                "# to add multiple items to the list use 'extend'\n",
                "extra_steps = [fc.Point(x=50, y=50),fc.Point(x=60, y=60),fc.Point(x=70, y=70)]\n",
                "steps.extend(extra_steps)\n",
                "\n",
                "# transform the design to gcode and print to screen\n",
                "print(fc.transform(steps, 'gcode', show_tips=False))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "58edb21b",
            "metadata": {},
            "source": [
                "#### use a python loop to concisely add steps to a ***design***"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "7b77923c",
            "metadata": {},
            "outputs": [],
            "source": [
                "steps = []\n",
                "for i in range(11):\n",
                "    steps.append(fc.Point(x=10+i,y=10+i,z=0))\n",
                "print(fc.transform(steps, 'gcode', show_tips=False))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "ad8e3190",
            "metadata": {},
            "source": [
                "#### transform a ***design*** into a 'plot' ***result***\n",
                "\n",
                "plot are created from the ***design*** data. it does **not** inspect and plot a gcode file. this means it can utilize design data that may not be included in gcode (e.g. color)\n",
                "\n",
                "info about changing the style of the plot (colors, axes, etc.) can be found in a [plot formatting notebook](https://colab.research.google.com/github/FullControlXYZ/fullcontrol/blob/master/tutorials/colab/plot_controls_colab.ipynb)\n",
                "\n",
                "the following design loops 25 times to achieve 25 layers with 4 points in each"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "20b93af7-beaa-4bf3-9115-b1165cac8eeb",
            "metadata": {},
            "outputs": [],
            "source": [
                "layer_height = 0.2\n",
                "steps = []\n",
                "for i in range(25):\n",
                "    steps.append(fc.Point(x=50,y=55,z=i*layer_height))\n",
                "    steps.append(fc.Point(x=55+i*layer_height/2,y=50,z=i*layer_height/2))\n",
                "    steps.append(fc.Point(x=50,y=45,z=i*layer_height))\n",
                "    steps.append(fc.Point(x=45-i*layer_height/2,y=50,z=i*layer_height/2))\n",
                "fc.transform(steps, 'plot', fc.PlotControls(style='line'))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "1b2c5e69-24c2-49fe-b62a-51501e7b94d6",
            "metadata": {},
            "source": [
                "#### use mathematical design to make complex print paths\n",
                "\n",
                "this design creates a helix print path that fluctuates in height and radius\n",
                "\n",
                "the tau, sin and cos functions need to be imported from python's built-in math module "
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "5ba61a49",
            "metadata": {},
            "outputs": [],
            "source": [
                "from math import sin, cos, tau\n",
                "steps = []\n",
                "for i in range(10000):\n",
                "    angle = tau*i/200\n",
                "    offset = (1.5*(i/10000)**2)*cos(angle*6)\n",
                "    steps.append(fc.Point(x=(6+offset)*sin(angle), y=(6+offset)*cos(angle), z=((i/200)*0.1)-offset/2))\n",
                "fc.transform(steps, 'plot', fc.PlotControls(style='line'))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "5d4e2df4",
            "metadata": {},
            "source": [
                "#### use python *'list comprehension'* to create the list of steps efficiently"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "4de121e5",
            "metadata": {},
            "outputs": [],
            "source": [
                "from random import random\n",
                "steps = [fc.Point(x=50*random(),y=50*random(),z=i*0.01) for i in range(1000)]\n",
                "fc.transform(steps, 'plot', fc.PlotControls(style='line'))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "352e529f",
            "metadata": {},
            "source": [
                "## III - common types of ***state***"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "1b923934",
            "metadata": {},
            "source": [
                "you can change the ***state*** of more than the nozzle position\n",
                "\n",
                "a few examples are shown here - more details about the various types of ***state*** are given in the [state objects notebook](https://colab.research.google.com/github/FullControlXYZ/fullcontrol/blob/master/tutorials/colab/state_objects_colab.ipynb)\n",
                "\n",
                "some changes to ***state*** result in a new line of gcode (e.g. changing fan speed)\n",
                "\n",
                "other changes do not, but influence future lines of gcode (e.g. changing print speed only manifests in gcode when the next G1 movement command occurs) "
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "4965d803",
            "metadata": {},
            "source": [
                "#### e.g. print speed, fan speed and hotend temperature"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "9a0a0a30",
            "metadata": {},
            "outputs": [],
            "source": [
                "steps = []\n",
                "steps.append(fc.Point(x=0,y=0,z=0))\n",
                "steps.append(fc.Point(x=20))\n",
                "steps.append(fc.Point(x=40))\n",
                "steps.append(fc.Printer(print_speed=750))\n",
                "steps.append(fc.Point(x=60))\n",
                "steps.append(fc.Point(x=80))\n",
                "steps.append(fc.Fan(speed_percent=50))\n",
                "steps.append(fc.Hotend(temp=205))\n",
                "steps.append(fc.Point(x=100))\n",
                "print(fc.transform(steps, 'gcode', show_tips=False))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "abf0da4b",
            "metadata": {},
            "source": [
                "#### turn the extruder off and on"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "f19df93f",
            "metadata": {},
            "outputs": [],
            "source": [
                "steps = []\n",
                "steps.append(fc.Point(x=0,y=0,z=0.2))\n",
                "steps.append(fc.Point(x=5, y=20))\n",
                "steps.append(fc.Point(x=10, y=0))\n",
                "steps.append(fc.Extruder(on=False))\n",
                "steps.append(fc.Point(x=0,y=0,z=0.4))\n",
                "steps.append(fc.Extruder(on=True))\n",
                "steps.append(fc.Point(x=5, y=20))\n",
                "steps.append(fc.Point(x=10, y=0))\n",
                "steps.extend(fc.travel_to(fc.Point(x=0,y=0,z=0.6)))\n",
                "steps.append(fc.Point(x=5, y=20))\n",
                "steps.append(fc.Point(x=10, y=0))\n",
                "fc.transform(steps, 'plot', fc.PlotControls(style='line'))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "5ca65789",
            "metadata": {},
            "source": [
                "## IV - annotations and custom commands"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "26d925e2",
            "metadata": {},
            "source": [
                "#### add comments for the gcode ***result***"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "d7a94eb8",
            "metadata": {},
            "outputs": [],
            "source": [
                "steps = []\n",
                "steps.append(fc.Point(x=0, y=0, z=0))\n",
                "steps.append(fc.GcodeComment(text='the next line of gcode will print to x=20'))\n",
                "steps.append(fc.Point(x=20))\n",
                "steps.append(fc.Point(x=40))\n",
                "steps.append(fc.GcodeComment(end_of_previous_line_text='this line of gcode prints to x=40'))\n",
                "print(fc.transform(steps, 'gcode', show_tips=False))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "ea5941ab-fe38-45d6-83cc-c179c6ff6f2d",
            "metadata": {},
            "source": [
                "#### add custom gcode commands\n",
                "\n",
                "gcode commands can be manually written\n",
                "\n",
                "alternatively, the printer has a list of commands that can be called by their id, which allows automatic conversion of commands for different printers' gcode styles"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "949462e4-951e-4863-8c36-a0e8794a7836",
            "metadata": {},
            "outputs": [],
            "source": [
                "steps = []\n",
                "steps.append(fc.Point(x=0, y=0, z=0))\n",
                "steps.append(fc.Point(x=20))\n",
                "steps.append(fc.ManualGcode(text=\"G4 P2000 ; pause for 2 seconds\"))\n",
                "steps.append(fc.PrinterCommand(id='retract'))\n",
                "print(fc.transform(steps, 'gcode', show_tips=False))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "26d925e2",
            "metadata": {},
            "source": [
                "#### add annotations to the 'plot' ***result***\n",
                "\n",
                "more details about plot annotations can be found in the [plot formatting notebook](https://colab.research.google.com/github/FullControlXYZ/fullcontrol/blob/master/tutorials/colab/plot_controls_colab.ipynb)"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "9a3fbe90",
            "metadata": {},
            "outputs": [],
            "source": [
                "steps = []\n",
                "for i in range(3):\n",
                "    steps.append(fc.Fan(speed_percent=50*i))\n",
                "    for j in range (3):\n",
                "        steps.append(fc.Point(x=20, y=20+5*j+30*i, z=0+0.1*j))\n",
                "        steps.append(fc.PlotAnnotation(label=\"Height: \" + str(0+0.1*j) + \" mm\"))\n",
                "        steps.append(fc.Point(x=50, y=20+5*j+30*i, z=0+0.1*j))\n",
                "    steps.append(fc.PlotAnnotation(label=\"Fan speed: \" + str(50*i) + \"%\"))\n",
                "fc.transform(steps, 'plot', fc.PlotControls(style='line'))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "7cb180a1",
            "metadata": {},
            "source": [
                "## V - adjust the way the ***design*** is converted into the ***result***"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "57670fd6",
            "metadata": {},
            "source": [
                "### 1. *GcodeControls* adjust gcode creation\n",
                "\n",
                "some examples are given below\n",
                "\n",
                "for more info about gcode controls, see the [gcode formatting notebook](https://colab.research.google.com/github/FullControlXYZ/fullcontrol/blob/master/tutorials/colab/gcode_controls_colab.ipynb)"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "cd8f65c5",
            "metadata": {},
            "source": [
                "#### save gcode to file\n",
                "\n",
                "run the next cell to save gcode as a file in the same folder as this jupyter notebook"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "e1d79340",
            "metadata": {},
            "outputs": [],
            "source": [
                "steps = [fc.Point(x=10, y=10, z=0), fc.Point(x=20), fc.Point(y=20)]\n",
                "fc.transform(steps, 'gcode', fc.GcodeControls(save_as=\"my_design\"))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "4fce5133",
            "metadata": {},
            "source": [
                "#### change initial print settings\n",
                "\n",
                "in addition to changing the ***state*** during the printing process, as shown in the above examples, you can set the ***state*** of initial print settings"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "be3bafc7",
            "metadata": {},
            "outputs": [],
            "source": [
                "steps = [fc.Point(x=10, y=10, z=0), fc.Point(x=20), fc.Point(y=20)]\n",
                "print('########\\n######## Default initial conditions:\\n########')\n",
                "print(fc.transform(steps, 'gcode', show_tips=False))\n",
                "gcode_controls = fc.GcodeControls(initialization_data={\"print_speed\": 600, \"travel_speed\": 5750})\n",
                "print('\\n########\\n######## Modified initial conditions (see F8000 changed to F5750 and F1000 changed to F600):\\n########')\n",
                "print(fc.transform(steps, 'gcode', gcode_controls, show_tips=False))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "3dbe34e3",
            "metadata": {},
            "source": [
                "#### change format of gcode ***result*** for different printers\n",
                "\n",
                "running the code in the next cell will generate gcode for two different printers and print the first 8 lines to screen"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "8dffae29",
            "metadata": {},
            "outputs": [],
            "source": [
                "steps = [fc.Point(x=10, y=10, z=0), fc.Point(x=20), fc.Point(y=20)]\n",
                "prusa_gcode = fc.transform(steps, 'gcode', fc.GcodeControls(printer_name='prusa_i3', initialization_data={'relative_e': False}), show_tips=False)\n",
                "ulti2plus_gcode = fc.transform(steps, 'gcode', fc.GcodeControls(printer_name='ultimaker2plus', initialization_data={'relative_e': True}), show_tips=False)\n",
                "\n",
                "print('########\\n######## prusa gcode - first 8 lines:\\n######## ')\n",
                "gcode_list = (prusa_gcode.split('\\n'))\n",
                "print('\\n'.join(gcode_list[0:8]))\n",
                "\n",
                "print('\\n\\n########\\n######## ultimaker gcode - first 8 lines:\\n######## ')\n",
                "gcode_list = (ulti2plus_gcode.split('\\n'))\n",
                "print('\\n'.join(gcode_list[0:8]))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "0533b210",
            "metadata": {},
            "source": [
                "### 2. *PlotControls* adjust how plot data is created and displayed\n",
                "\n",
                "#### output the raw plot data for use in alternative plottings modules/software\n",
                "\n",
                "it's also possible to change color, line-width, etc. - for more info about plot controls, see the [plot formatting notebook](https://colab.research.google.com/github/FullControlXYZ/fullcontrol/blob/master/tutorials/colab/plot_controls_colab.ipynb)\n",
                "\n",
                "the next code cell prints the raw plot data to screen and also creates the associated 3D plot for comparison"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "01bfe92f",
            "metadata": {},
            "outputs": [],
            "source": [
                "plot_controls = fc.PlotControls(raw_data=True)\n",
                "steps = [fc.Point(x=10, y=10, z=0), fc.Point(x=30, z=0.5), fc.Point(x=10, z=1), fc.PlotAnnotation(label=\"End\")]\n",
                "plot_data = fc.transform(steps, 'plot', plot_controls)\n",
                "print(plot_data)\n",
                "fc.transform(steps, 'plot', fc.PlotControls(style='line'))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "6a73b5c6",
            "metadata": {},
            "source": [
                "## VI - use FullControl geometry functions to create the ***design***\n",
                "\n",
                "a few demo functions are shown here - for more details about geometry functions, see the [geometry functions notebook](https://colab.research.google.com/github/FullControlXYZ/fullcontrol/blob/master/tutorials/colab/geometry_functions_colab.ipynb)"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "38df96ce",
            "metadata": {},
            "source": [
                "#### e.g. rectangle"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "8468237f",
            "metadata": {},
            "outputs": [],
            "source": [
                "steps = fc.rectangleXY(fc.Point(x=0, y=0, z=0.2), 20, 4)\n",
                "fc.transform(steps, 'plot', fc.PlotControls(color_type='print_sequence', style='line'))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "efca524e",
            "metadata": {},
            "source": [
                "#### e.g. copy geometry to make a linear array"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "9f93195b",
            "metadata": {},
            "outputs": [],
            "source": [
                "steps = fc.rectangleXY(fc.Point(x=0, y=0, z=0.2), 20, 4)\n",
                "steps = fc.move(steps,fc.Vector(z=0.2),copy=True, copy_quantity=25)\n",
                "fc.transform(steps, 'plot', fc.PlotControls(style='line'))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "4a3bb9b8",
            "metadata": {},
            "source": [
                "#### e.g. helix"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "ddcf3650",
            "metadata": {},
            "outputs": [],
            "source": [
                "centre_point = fc.Point(x=50, y=50, z=0)\n",
                "steps = fc.helixZ(centre_point, 8, 6, 0, 30, 0.15, 20*64)\n",
                "fc.transform(steps, 'plot', fc.PlotControls(style='line'))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "27fcfde4",
            "metadata": {},
            "source": [
                "#### combine geometry functions to quickly achieve interesting print paths\n",
                "- create a squarewave\n",
                "- copy it with 180-degree rotation\n",
                "- repeat it for 25 layers"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "5302205b",
            "metadata": {},
            "outputs": [],
            "source": [
                "steps = fc.squarewaveXY(fc.Point(x=20, y=50, z=0), fc.Vector(x=1, y=0), 10, 5, 10)\n",
                "steps = fc.move_polar(steps,fc.Point(x=67.5, y=45, z=0), 0, tau/2, copy=True)\n",
                "steps = fc.move(steps, fc.Vector(z=0.2), copy=True, copy_quantity=60)\n",
                "fc.transform(steps, 'plot', fc.PlotControls(style='line'))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "1dec159a",
            "metadata": {},
            "source": [
                "#### design in polar coordinates\n",
                "\n",
                "the FullControl 'polar_to_point' function converts polar coordinates into Cartesian points\n",
                "\n",
                "combining it with python's built-in 'list comprehension' capabilities allows a complex list of steps to be created with one line of code"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "87f9b678",
            "metadata": {},
            "outputs": [],
            "source": [
                "steps=[fc.polar_to_point(centre=fc.Point(x=0, y=0, z=i*0.001), radius=10+5*random(), angle=i*tau/13.8) for i in range(4000)]\n",
                "fc.transform(steps, 'plot', fc.PlotControls(neat_for_publishing=True, zoom=0.7, style='line'))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "a39ebafd",
            "metadata": {},
            "source": [
                "#### create custom geometry functions\n",
                "\n",
                "the next example is similar to the earlier squarewave example, except it uses a **custom** triangle wave function instead of a function built into FullControl\n",
                "\n",
                "if you create useful geometry functions, add them to FullControl so everyone can benefit (see contribution guidelines on [github](https://github.com/FullControlXYZ/fullcontrol))"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "3d7cdece",
            "metadata": {},
            "outputs": [],
            "source": [
                "def tri_wave(start_point: fc.Point, amplitude: float, period_length: float, periods: int) -> list:\n",
                "    tri_wave_steps = []\n",
                "    for i in range(periods*2+1):\n",
                "        tri_wave_steps.append(fc.Point(x=start_point.x+i*period_length/2, y=start_point.y+amplitude*(i % 2), z=start_point.z))\n",
                "    return tri_wave_steps\n",
                "\n",
                "steps = tri_wave(fc.Point(x=20, y=50, z=0), 10, 10, 10)\n",
                "steps.extend(tri_wave(fc.Point(x=120, y=40, z=0), -10, -10, 10))\n",
                "steps = fc.move(steps, fc.Vector(z=0.2), copy=True, copy_quantity=60)\n",
                "fc.transform(steps, 'plot', fc.PlotControls(style='line'))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "d8af1e17",
            "metadata": {},
            "source": [
                "## VII - next steps\n",
                "\n",
                "enhanced functionality has been developed for in-house research and is intended for public release as time allows:\n",
                "- multi-axis\n",
                "    - full walk-through documentation for a 5-axis tool changer, including hardware, configuration, calibration, and more (release imminent)\n",
                "    - toolpath design directly in FullControl\n",
                "        - preliminary version already included in the 'FullControl lab' - see the example below, and the [5-axis demo notebook](https://colab.research.google.com/github/FullControlXYZ/fullcontrol/blob/master/tutorials/colab/lab_five_axis_demo_colab.ipynb)\n",
                "- multi-tool\n",
                "- multi-hardware\n",
                "- geometry import and interrogation (STL and similar)\n",
                "- in-process inspection and correction\n",
                "- upload of models to www.fullcontrol.xyz\n",
                "    - if you're able and interested in turning www.fullcontrol.xyz into the ***best website ever*** for additive manufacturing, please get in touch: [info@fullcontrol.xyz](mailto:info@fullcontrol.xyz)\n",
                "\n",
                "additional functionality beyond that listed above is planned for ongoing research by Andy Gleadall, which will also be made open-source whenever possible\n",
                "\n",
                "please improve FullControl and add capabilities to it\n",
                "- e.g. to support journal papers that present new methods for additive manufacturing by making those methods available to everyone via FullControl"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "19b57063",
            "metadata": {},
            "source": [
                "#### five_axis example\n",
                "\n",
                "this example shows a wavey helical print path, where the model is continuously rotating while the nozzle gradually moves away from the print platform\n",
                "\n",
                "the part is tilted to orient the nozzle perpendicular(ish) to the wavey walls at all points\n",
                "\n",
                "color data is added to visualize the b axis"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "e5677647",
            "metadata": {},
            "outputs": [],
            "source": [
                "import lab.fullcontrol.fiveaxis as fc5\n",
                "from math import sin, cos, tau\n",
                "steps = []\n",
                "for i in range(10001):\n",
                "    angle = tau*i/200\n",
                "    offset = (1.5*(i/10000)**2)*cos(angle*6)\n",
                "    steps.append(fc5.Point(x=(6+offset)*sin(angle), y=(6+offset)*cos(angle), z=((i/200)*0.1)-offset/2, b=(offset/1.5)*30, c=angle*360/tau))\n",
                "for step in steps:\n",
                "    if type(step).__name__ == 'Point':\n",
                "        # color is a gradient from B=0 (blue) to B=45 (red)\n",
                "        step.color = [((step.b+30)/60), 0, 1-((step.b+30)/60)]\n",
                "steps.append(fc5.PlotAnnotation(point=fc5.Point(x=0, y=0, z=8.75), label='color indicates B axis (tilt)'))\n",
                "steps.append(fc5.PlotAnnotation(point=fc5.Point(x=0, y=0, z=7.5), label='-30 deg (blue) to +30 deg (red)'))\n",
                "gcode = fc5.transform(steps,'gcode')\n",
                "print('final ten gcode lines:\\n' + '\\n'.join(gcode.split('\\n')[-10:]))\n",
                "fc5.transform(steps, 'plot', fc5.PlotControls(color_type='manual', hide_axes=False, zoom=0.75, style='line'))"
            ]
        }
    ],
    "metadata": {
        "kernelspec": {
            "display_name": "Python 3 (ipykernel)",
            "language": "python",
            "name": "python3"
        },
        "language_info": {
            "codemirror_mode": {
                "name": "ipython",
                "version": 3
            },
            "file_extension": ".py",
            "mimetype": "text/x-python",
            "name": "python",
            "nbconvert_exporter": "python",
            "pygments_lexer": "ipython3",
            "version": "3.11.3"
        },
        "vscode": {
            "interpreter": {
                "hash": "2b13a99eb0d91dd901c683fa32c6210ac0c6779bab056ce7c570b3b366dfe237"
            }
        }
    },
    "nbformat": 4,
    "nbformat_minor": 5
}
